﻿using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text.Encodings.Web;
using Nxg.Blog.Core.Documents;
using Nxg.Blog.Core.Extensions;

namespace Nxg.Blog.Core.Commands.Posts
{
    public class NewPostCommand
    {
        public int Id { get; set; }
        public Author Author { get; set; }

        [Required]
        public string Title { get; set; }

        [Required]
        public string TitleSlug { get; set; }

        [Required]
        public string MarkDown { get; set; }

        [Required]
        public string Content { get; set; }

        public string Tags { get; set; }

        [Required]
        public DateTime PubDate { get; set; }

        [Required]
        public bool Published { get; set; }
    }

    public class NewPostCommandInvoker : ICommandInvoker<NewPostCommand, CommandResult>
    {
        private readonly DataContext _db;
        public NewPostCommandInvoker(DataContext db)
        {
            _db = db;
        }

        public CommandResult Execute(NewPostCommand command)
        {
            var post = command.Id == 0 ? new BlogPost { Id = command.Id } : _db.Post.SingleOrDefault(x => x.Id == command.Id);
            if (post == null)
            {
                return new CommandResult($"post {command.Id} no exits");
            }
            var titleSlug = command.TitleSlug.IsNullOrWhitespace() ? command.Title.Trim().ToSlug() : command.TitleSlug.Trim().ToSlug();

            if (_db.Post.Any(x => x.TitleSlug == titleSlug && x.Id != command.Id))
            {
                return new CommandResult($"TitleSlug {titleSlug} aready exits");
            }
            post.TitleSlug = titleSlug;
            post.AuthorEmail = command.Author.Email;
            post.AuthorDisplayName = command.Author.DisplayName;
            post.MarkDown = UrlEncoder.Default.Encode(command.MarkDown);
            post.Content = command.Content;
            post.PubDate = command.PubDate;
            post.Status = command.Published ? PublishStatus.Published : PublishStatus.Draft;
            post.Title = command.Title;
            if (!command.Tags.IsNullOrWhitespace())
            {
                var tags = command.Tags.Trim().Split(',').Select(s => s.Trim());
                post.Tags = string.Join(',', tags);
                foreach (var tag in tags)
                {
                    var slug = tag.ToSlug();
                    var tagEntry = _db.Tag.Where(x => x.Slug == slug).FirstOrDefault();
                    if (tagEntry == null)
                    {
                        tagEntry = new Documents.Tag
                        {
                            Slug = slug,
                            Name = tag,
                            PostCount = 1
                        };
                        _db.Tag.Add(tagEntry);
                    }
                    else
                    {
                        tagEntry.PostCount++;
                    }
                }
            }
            else
                post.Tags = "";
            if (command.Id == 0)
            {
                _db.Post.Add(post);
            }
            else
            {
                _db.Update(post);
            }

            _db.SaveChanges();
            return CommandResult.SuccessResult;
        }
    }
}